﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="Background.cs" company="">
//   
// </copyright>
// <summary>
//   The background.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

/* 
 * Author: Mikkel Thordal Andersen
 * Created: 28.11.2011
 */
namespace ITU_vs_Zombies.Graphics
{
    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Linq;
    using System.Runtime.InteropServices;

    using ITU_vs_Zombies.Game;
    using ITU_vs_Zombies.Movement;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;

    using Color = Microsoft.Xna.Framework.Color;
    using Rectangle = System.Drawing.Rectangle;

    /// <summary>
    /// The background.
    /// </summary>
    [Serializable]
    public class Background : IGraphicsHelper
    {
        #region Constants and Fields

        /// <summary>
        /// The images.
        /// </summary>
        [NonSerialized]
        public Texture2D[] Images;

        /// <summary>
        /// The image.
        /// </summary>
        private readonly string image;

        /// <summary>
        /// The position.
        /// </summary>
        private Vector2 position;

        /// <summary>
        /// The scale.
        /// </summary>
        private float scale;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="Background"/> class.
        /// </summary>
        /// <param name="image">
        /// The image.
        /// </param>
        public Background(string image)
        {
            this.image = image;

            this.position = new Vector2(0, 0);
        }

        #endregion

        #region Public Properties

        /// <summary>
        /// Gets Height.
        /// </summary>
        public float Height
        {
            get
            {
                return this.Images[0].Height;
            }
        }

        /// <summary>
        /// Gets or sets Position.
        /// </summary>
        public Vector2 Position
        {
            get
            {
                return this.position;
            }
        }

        /// <summary>
        /// Gets Width.
        /// </summary>
        public float Width
        {
            get
            {
                return this.Images.Aggregate(0.0f, (current, texture2D) => current + texture2D.Width) * this.scale;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The draw.
        /// </summary>
        /// <param name="spriteBatch">
        /// The sprite batch.
        /// </param>
        public void Draw(SpriteBatch spriteBatch)
        {
            for (int i = 0; i < this.Images.Length; i++)
            {
                spriteBatch.Draw(
                    this.Images[i], 
                    new Vector2((i * this.Images[i].Width * this.scale) + this.position.X, 0), 
                    new Microsoft.Xna.Framework.Rectangle(0, 0, this.Images[i].Width, this.Images[i].Height), 
                    Color.White, 
                    0.0f, 
                    Vector2.Zero, 
                    this.scale, 
                    SpriteEffects.None, 
                    0);
            }
        }

        /// <summary>
        /// The initialize position.
        /// </summary>
        public void InitializePosition()
        {
            this.position.X = 0;
        }

        /// <summary>
        /// The load content.
        /// </summary>
        public void LoadContent()
        {
            Image b = Image.FromFile(Client.Content.RootDirectory + "\\" + this.image + ".jpg");

            // The number of split-ups is calculated by dividing with the allowed width of the image 
            this.Images = new Texture2D[(int)Math.Ceiling((double)b.Width / 2048)];

            int distanceX = 0;

            for (int i = 0; i < this.Images.Length; i++)
            {
                this.Images[i] =
                    GetTexture2DFromImage(
                        CropImage(b, new Rectangle(distanceX, 0, b.Width / this.Images.Length, b.Height)));

                distanceX += b.Width / this.Images.Length;
            }

            this.scale = Client.GraphicsDevice.Viewport.Height / this.Height;
        }

        /// <summary>
        /// The move.
        /// </summary>
        /// <param name="m">
        /// The m.
        /// </param>
        /// <param name="speed">
        /// The speed.
        /// </param>
        public void Move(MovementsEnum m, uint speed)
        {
            switch (m)
            {
                case MovementsEnum.Left:
                    this.position.X += speed;
                    break;
                case MovementsEnum.Right:
                    this.position.X -= speed;
                    break;
            }

            this.position.X = MathHelper.Clamp(this.position.X, -(this.Width - Client.GraphicsDevice.Viewport.Width), 0);
        }

        /// <summary>
        /// The update.
        /// </summary>
        /// <param name="gameTime">
        /// The game time.
        /// </param>
        /// <param name="position">
        /// The position.
        /// </param>
        public void Update(GameTime gameTime, Vector2 position)
        {
        }

        #endregion

        #region Methods

        /// <summary>
        /// The crop image.
        /// </summary>
        /// <param name="img">
        /// The img.
        /// </param>
        /// <param name="cropArea">
        /// The crop area.
        /// </param>
        /// <returns>
        /// An image.
        /// </returns>
        private static Image CropImage(Image img, Rectangle cropArea)
        {
            var bmpImage = new Bitmap(img);
            Bitmap bmpCrop = bmpImage.Clone(cropArea, bmpImage.PixelFormat);
            return bmpCrop;
        }

        /// <summary>
        /// The get texture 2 d from image.
        /// </summary>
        /// <param name="bitmap">
        /// The bitmap.
        /// </param>
        /// <returns>
        /// A texture.
        /// </returns>
        private static Texture2D GetTexture2DFromImage(Image bitmap)
        {
            var tex = new Texture2D(Client.GraphicsDevice, bitmap.Width, bitmap.Height, false, SurfaceFormat.Color);
            var b = new Bitmap(bitmap);

            BitmapData data = b.LockBits(
                new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);

            int bufferSize = data.Height * data.Stride;

            // create data buffer 
            var bytes = new byte[bufferSize];

            // copy bitmap data into buffer
            Marshal.Copy(data.Scan0, bytes, 0, bytes.Length);

            // copy our buffer to the texture
            tex.SetData(bytes);

            // unlock the bitmap data
            b.UnlockBits(data);

            return tex;
        }

        #endregion
    }
}